from PyQt4.QtCore import QObject,QThread,pyqtSignal
import time
import os
from operator import itemgetter, attrgetter
from KDataBase.KQueryDB import KQueryDB
from KDataBase.KDBUtility import KDBUtility
import itertools
class KAbstractDBProvider(QObject):
	## signals 
	ProgressUpdated=pyqtSignal(str)
	finished=pyqtSignal()
	@property
	def Stop(self):
		return self.stopped
	@Stop.setter
	def Stop(self,value):
		self.stopped=value   
	def __init__(self,parent,database):
		QObject.__init__(self)
		self.db=database
		self.bulklimit=5000 # the bulk insert records limit
		self.stockcountlimit=300 # update progress every stockcountlimit stocks
	def UpdateAllHistory(self,path,timerange):
		## update database based on an incremetal basis
		pass	

	def UpdateProgress(self,text):
		self.ProgressUpdated.emit(text)
	def BulkInsertBySingleStockDate(self,market,curinsertcount,curcotent):
	# insert one date of stock in bulk mode
		try:
			self.cldailystocks.insert(curcotent)
			elapsed=(time.clock()-self.start)
			message='Importing - M: %s S#: %dK T:%.2f' %(market,curinsertcount/1000,elapsed)
		except:
			message='error occured during bulk inserting'
		self.UpdateProgress(message)
		print(message)
		
	def InsertBySingleStockDate(self,market,curinsertcount,newcondition,curcotent,newcontent):
	# insert one date of stock in single stock mode,!!!require futher test
		curinsertcount=curinsertcount+1
		try: 
			self.cldailystocks.update(newcondition,newcontent[0],True)
			if curinsertcount%self.bulklimit==0:
				elapsed=(time.clock()-self.start)
				message='Importing - M: %s S#: %dK T:%.2f' %(market,curinsertcount,elapsed)
				self.UpdateProgress(message)
				print(message)
		except:
			pass 
		return (curinsertcount,curcotent) 
	def UpdateSingleStock(self,mdic,folders,stockdb):
	# merge newcontents into existing database record
		if len(mdic)==0:
			return True	

		forceoverwrite=KDBUtility.OverrideExstingFileWhenDailyUpdate()

		allsymboldic={}# store all daily price of symbol based dict.
		for each_day in mdic: # parse each date
			each_daystr=str(each_day)
			dailypathname=folders[0]+r'/'+each_daystr+'.txt'
			minpathname=folders[1]+r'/'+each_daystr+'.txt'
			if forceoverwrite==True:
				dowrite=True; # force write from setting
			elif not ( os.path.exists(dailypathname) and os.path.exists(minpathname)):
				dowrite=True;
			else:
				dowrite=False;
				continue # skip existing file.


			dailydic=mdic[each_day]
			if dowrite==True:
				dailyfile = open(dailypathname, "w")
				minfile = open(minpathname, "w")
			for each_symbol in sorted(dailydic): # parse each symbol
				symdic=dailydic[each_symbol]

				#generate the data of this symbol on this date
				pblocks=symdic['price']
				pblocks=zip(*pblocks)
				dailyvec=[pblocks[0][0],max(pblocks[1]),min(pblocks[2]),pblocks[3][-1],sum(pblocks[4])]
				minvec=([symdic['time'],pblocks[0],pblocks[1],pblocks[2],pblocks[3],pblocks[4]])

				#update into allsymboldic
				if each_symbol not in allsymboldic:
					allsymboldic[each_symbol]=[]
				tempsymboldic=allsymboldic[each_symbol]
				dailyvec.insert(0,each_day)
				tempsymboldic.append(dailyvec)

				if dowrite==True:
					#writing dialy file
					dailyfile.write("%s " %each_symbol)
					[dailyfile.write("%s "%x) for x in dailyvec]
					dailyfile.write("\n")

					#writing min file
					minfile.write("%s " %each_symbol)
					for col_index in range(0,len(minvec[0])):
						for row_index in range(0,len(minvec)):
							minfile.write("%s "%minvec[row_index][col_index])
					minfile.write("\n")	
			if dowrite==True:				
				dailyfile.close()
				minfile.close()
			self.UpdateProgress("Writing File For Date: %d"%each_day)
		self.__MergeDailyStockData(allsymboldic,stockdb)
		
	def __MergeDailyStockData(self,symobldic,stockdb):
		# merge daily stock data in symobldic in to current database
		totalnum=0
		for each_symbol in sorted(symobldic,reverse=True):
			curdata=symobldic[each_symbol]
			curdate=[x[0] for x in curdata]
			cursor=stockdb.find_one({"symbol":each_symbol.upper()})
			if cursor and (curdate in cursor['date']): # do not go ahead if no new dates introduced
				continue 
			# merge data
			alldata=[]
			if not (cursor is None):
				rangevec=range(0,len(cursor['date']))
				[cursor['price'][x].insert(0,int(cursor['date'][x]))  for x in rangevec] # merge date and price
				alldata=cursor['price']
			oldnum=len(alldata)
			alldata.extend(curdata) #merge with new data
			newdata=sorted(alldata, key=itemgetter(0), reverse=False) # sort based on data
			#uniquedata=[newdata[0],]
			#uniquedata=list(newdata[x] for x in range(1,len(newdata)) if newdata[x-1][0]!=newdata[x][0])
			uniquedata=list(next(mgroup) for _,mgroup in itertools.groupby(newdata,lambda x:x[0])) # remove duplicates
			newdates=[x[0] for x in uniquedata]
			newprice=[x[1:6] for x in uniquedata]
			# cache latest price and date into field "latest info"
			latestinfo=[newprice[-1],newdates[-1]]
			#update data into database
			newcondition={"symbol":each_symbol.upper()}
			upcontents={"symbol":each_symbol.upper(),"date":newdates,"price":newprice,"latestinfo":latestinfo}
			stockdb.update(newcondition,upcontents,True)	
			newnum=len(uniquedata)
			totalnum+=newnum-oldnum
			print("Merged S# %s, add %d dates" %(each_symbol,newnum-oldnum))
		avenum=0 if len(symobldic)==0 else totalnum/len(symobldic)
		self.UpdateProgress("Merged S# %s, add %d dates on avarege." %(len(symobldic),avenum))

